//
// Created by 刘进伟 on 2018/5/19.
//

#include <string>
#include <sstream>
#include "FileRW.h"
#include "Common.h"

FileRW::FileRW(const char *fileName)
{
    srcFile = fopen(fileName, "r");
    char specChar[] = { '=', '<', '+', '-', '*', '/', '(', ')', '.', ':', ';', ',', '[', ']', -1, '\'' };
    CharType specCharType[] = { CTEQ, CTLT, CTPLUS, CTMINUS, CTTIMES, CTOVER, CTLPAREN,
                                CTRPAREN, CTDOT, CTCOLON, CTSEMI, CTCOMMA, CTLMIDPAREN,
                                CTRMIDPAREN, CTENDOFILE, CTQUOTE };
    std::string specWord[] = { ":=", "=", "<", "+", "-", "*", "/", "(", ")", ".", ":", ";", ",", "[", "]", ".." };
    LexType specWordType[] = { ASSIGN, EQ, LT, PLUS, MINUS, TIMES, OVER, LPAREN, RPAREN,
                               DOT, COLON, SEMI, COMMA, LMIDPAREN, RMIDPAREN, UNDERANGE };
    if (srcFile == NULL) {
        printf("open file %s error\n", fileName);
        exit(0);
    } else {
        printf("open file complete\n");
        readFile();
        for (char i = 'a'; i <= 'z'; i++) {
            CHAR_SET[i] = LETTER;
        }
        for (char i = 'A'; i <= 'Z'; i++) {
            CHAR_SET[i] = LETTER;
        }
        for (char i = '0'; i <= '9'; i++) {
            CHAR_SET[i] = CharType::NUMBER;
        }
        for (int i = 0; i < 16; ++i) {
            CHAR_SET[specChar[i]] = specCharType[i];
        }
        for (int i = 0; i < 16; i++) {
            WORD_SET[std::string(specWord[i])] = specWordType[i];
        }
        printf("CHAR_SET length:%d\n", CHAR_SET.size());
        printf("WORD_SET length:%d\n", WORD_SET.size());
    }
}

FileRW::~FileRW()
{
    fclose(srcFile);
}

//私有方法
char FileRW::readChar()
{
    if(currentLex<0){
        currentLex=0;
        return memLastChar;
    }
    if (currentLex == bufferLength) {
        readFile();
        if (currentLex == bufferLength) {
            return -1;
        } else {
            return inputBuffer[currentLex++];
        }
    } else {
        return inputBuffer[currentLex++];
    }
}

void FileRW::readFile()
{
    for(int i=currentLex-1;true;i--){
        if(inputBuffer[i]==' '|| inputBuffer[i]=='\r'){

        }else{
            memLastChar=inputBuffer[i];
            break;
        }
    }
    bufferLength = fread(inputBuffer, sizeof(char), BUFFERLENGTH, srcFile);
    if(bufferLength<BUFFERLENGTH){
        inputBuffer[bufferLength++]=-1;
    }
    currentLex = 0;
}

CharType FileRW::findCharType(char &obj)
{
    std::map<const char, CharType>::iterator temp = CHAR_SET.find(obj);
    if (temp == CHAR_SET.end()) {
        return CharType::OTHERS;
    }
    return temp->second;
}

bool FileRW::isNumber(char *str)
{
    std::stringstream sstr;
    sstr.str(str);
    double a;
    char b;
    if (!(sstr >> a)) {
        return false;
    } else {
        if (sstr >> b) {
            return false;
        } else {
            return true;
        }
    }
}

//公有方法
Char &FileRW::getNextChar()
{
    struct Char *chartemp = new struct Char;
    struct Char &temp = *chartemp;
    char currentChar;
    bool enterFlag = true;
    currentChar = readChar();
    while (enterFlag) {
        switch (currentChar) {
            case '\n':
                temp.lex = currentChar;
                temp.lineNumber = lineNumber;
                temp.charType = findCharType(currentChar);
                lineNumber++;
                return temp;
            case '\r':
                currentChar = readChar();
                enterFlag = true;
                break;
            case 9:
                currentChar=readChar();
                enterFlag=true;
                break;
            case '{':
                while(currentChar!=-1 && currentChar!='}'){
                    currentChar=readChar();
                    if(currentChar=='\n'){
                        lineNumber++;
                    }
                }
                currentChar=readChar();
                break;
            default:
                enterFlag = false;
                break;
        }
    }
    temp.lex = currentChar;
    temp.lineNumber = lineNumber;
    temp.charType = findCharType(currentChar);
    return temp;
}

void FileRW::ungetNextChar()
{
    currentLex--;
    if(inputBuffer[currentLex]=='\n'){
        lineNumber--;
    }
}

void FileRW::setWordType(struct Token &token)
{
    //查找保留字
    for (int i = 0; i < MAXRESERVED; i++) {
        if (strcmp(reservedWords[i].str, token.content) == 0) {
            token.lexType = reservedWords[i].toke;
            return;
        }
    }
    //查找特殊字符
    std::map<std::string, LexType>::iterator it_word_set = WORD_SET.find(std::string(token.content));

    if (it_word_set == WORD_SET.end()) {
        //在ID，INTEGER，CHARC中确定类型
        if (token.content[0] == '\'') {
            token.lexType = LexType::CHARC;
            token.content[0] = token.content[1];
            token.content[1] = 0;
            return;
        }
        if (isNumber(token.content)) {
            token.lexType = LexType::INTC;
            return;
        }
        token.lexType = LexType::ID;
        return;
    } else {
        token.lexType = it_word_set->second;
        return;
    }
}
bool FileRW::writeFile(std::list<Token> &tokens)
{
    FILE *objFile = NULL;
    for (std::list<Token>::iterator it = tokens.begin(); it != tokens.end(); ++it)
        std::cout << "行号：" << it->lineNumber << " 类型：" << it->lexType
                  << " 内容：" << it->content << std::endl;
    return true;
}